\documentclass[a4paper,11pt]{article}

% \usepackage{fontspec}           % 用XeTeX排版中文需要用到的一个宏包
\usepackage{xeCJK}
% \usepackage{indentfirst}        % 自动首行缩进
\usepackage{graphicx}           % 插入图片需要的宏包
\usepackage{amssymb}            % AMS的数学宏包, 有时需要用到其中的一些数学符号
\usepackage{color}              % 可以定义各种颜色
\usepackage{framed}             % 显示代码环境的制作需要用到
\usepackage{float}              % 强大的浮动环境控制宏包
\usepackage[pagestyles]{titlesec}        % 定制页眉页脚
\usepackage[pdfauthor={高昌健},%
            pdftitle={迷宫问题个人报告},%
            colorlinks=true,%
            urlcolor=blue]{hyperref} % 为超链接增加颜色, 还有一些其它的好用功能
\usepackage[top=1in,bottom=1in,left=1.25in,right=1.25in]{geometry} % 设置页边距

\title{\textbf{题目：迷宫问题}}
\date{}
\author{学生：高昌健\qquad{}学号：2007081107\qquad{}班级：软件工程（.NET）1班}

% 自定义的几种颜色
\definecolor{shadecolor}{gray}{0.85}
\definecolor{darkblue}{RGB}{52,101,164}
\definecolor{darkgreen}{RGB}{78,154,6}

% 设置背景颜色
% \definecolor{bisque}{rgb}{.996,.891,.755}
% \pagecolor{bisque}

% 字体设置和针对中文的断行标准
\setmainfont[BoldFont=Adobe Heiti Std]{Adobe Song Std}
\setCJKmainfont[BoldFont=Adobe Heiti Std]{Adobe Song Std}
% \setsansfont{DejaVu Sans YuanTi Mono}
% \XeTeXlinebreaklocale ''zh''
% \XeTeXlinebreakskip=0pt plus 1pt minus 0.1pt

% 设置原文照排环境的字体
% \makeatletter
% \def\verbatim@font{\sffamily\small}
% \makeatother

% 设置chapter, section与subsection的格式
\titleformat{\chapter}{\centering\huge}{第\thechapter{}章}{1em}{\textbf}
\titleformat{\section}{\centering\LARGE}{\thesection}{1em}{\textbf}
\titleformat{\subsection}{\Large}{\thesubsection}{1em}{\textbf}

% 设置页眉页脚
% \newpagestyle{main}{%
%   \sethead[$\cdot$~\thepage~$\cdot$][][\thesection\quad%
%   \sectiontitle]{\thesection\quad\sectiontitle}{}{%
%   $\cdot$~\thepage~$\cdot$}
%   \setfoot{}{}{}\headrule}
% \pagestyle{main}
% \renewpagestyle{plain}{\sethead{}{}{}\setfoot{}{}{}}

% 去掉表头中的冒号
\makeatletter
\long\def\@makecaption#1#2{%
\vskip\abovecaptionskip
\sbox\@tempboxa{#1~~#2}%
\ifdim \wd\@tempboxa >\hsize
   #1~~#2\par
\else
   \global \@minipagefalse
   \hb@xt@\hsize{\hfil\box\@tempboxa\hfil}%
\fi
\vskip\belowcaptionskip}
\makeatother

% 将默认的英文重定义为中文
\renewcommand{\contentsname}{目录}
\renewcommand{\listfigurename}{插图目录}
\renewcommand{\listtablename}{表格目录}
% \renewcommand{\refname}{参考文献}
% \renewcommand{\abstractname}{摘要}
\renewcommand{\indexname}{索引}
\renewcommand{\tablename}{表}
\renewcommand{\figurename}{图}

\setlength{\parindent}{2.22em}  % 设置首行缩进的距离
\linespread{1.3}                % 设置行距

% XeTeX logo
\def\XeTeX{\leavevmode
  \setbox0=\hbox{X\lower.5ex\hbox{\kern-.15em\reflectbox{E}}\kern-.1667em 
    \TeX}%
  \dp0=0pt\ht0=0pt\box0}

\begin{document}
\maketitle

\section{需求分析（概要设计）}
我所负责的模块是随机读取迷宫地图文件，并且将地图文件存储到在主函数中建立的迷宫二维数组里。还有就是作为本小组的组长，为组员分配相应的任务。

\section{详细分析}
上述的模块有几个重点，下面详细叙述一下。
\subsection{迷宫地图文件的格式}
刚开始我们采用的是让电脑随机生成迷宫的方式，后来经过多次试验发现这种方法生成的迷宫太简单，不够复杂，而且很容易得到死迷宫。于是经过小组内部商讨决定，采用以地图文件的形式存储某个固定样式的迷宫，然后在程序执行时随机选取一个地图文件进行加载。但这就需要必须以某种固定的格式存储地图文件。于是我们制定了以下规则：
\begin{enumerate}
\item 地图文件名的格式为：mazemap+地图编号（00, 01, 02\ldots），以纯文本形式存储。
\item 地图统一大小为39$\times$39
\item 地图数据每行有39列，共39行。以0代表障碍，1代表通路。每个数据元素间以一个空格作为分隔。范例格式如下：
\[\begin{array}{cccccc}
  0 & 1 & 0 & 0 & 0 & \dots \\
  0 & 1 & 1 & 0 & 1 & \dots \\
  0 & 0 & 1 & 0 & 0 & \dots \\
  0 & 0 & 1 & 1 & 1 & \dots \\
  0 & 0 & 0 & 0 & 0 & \dots \\
  \vdots & \vdots & \vdots & \vdots & \vdots & \ddots \\
\end{array}\]
\item 地图文件的最后一行存储该迷宫的入口和出口的坐标，以(0, 0)作为起始坐标。先是入口坐标，然后是出口坐标，以一个空格作为分隔。
\item 所有地图文件都存储到源文件所在目录的map子目录中。
\end{enumerate}
\subsection{随机读取地图文件的实现}
由于编号的格式是固定的，所以用随机函数先生成一个介于1到最大地图数之间的数字，这可以用以下语句实现：
\begin{shaded}
\begin{verbatim}
int mapnumInt = random() % MAX_MAP_NUM + 1;
\end{verbatim}
\end{shaded}
然后把这个数字转换为字符型，这样便于同文件名的前缀进行拼接。最后就是拼接了，实现如下：
\begin{shaded}
\begin{verbatim}
mapfile = strcat(mapfile, MAP_FILE_PATH);
mapfile = strcat(mapfile, FILENAME_PREFIX);
mapfile = strcat(mapfile, mapnumStr);
\end{verbatim}
\end{shaded}
这样就得到了一个完整的包含路径与文件名的变量，可以很方便地传递给\verb|fopen()|函数了。
\subsection{从文件中读取数据}
因为迷宫的结构是用二维数组来存储的，并且用0来表示障碍，1表示通路，所以当打开文件以后所要做的就是将每一个数据存储到这个数组里。实现如下：
\begin{shaded}
\begin{verbatim}
fscanf(fp, "%d", &maze.maze[i][j]);
\end{verbatim}
\end{shaded}
然后就需要将文件指针移动到下一个数据：
\begin{shaded}
\begin{verbatim}
fseek(fp, 1, SEEK_CUR);
\end{verbatim}
\end{shaded}
像这样重复读取就行了，坐标的读取类似。

\section{程序流程图}
\begin{figure}[H]
  \centering
  \includegraphics[scale=.5]{flowchart.png}
\end{figure}

\section{源代码}
\begin{shaded}
\begin{verbatim}
/***** loadmaze.cpp *****/

// -1156203886

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

#define ROW_NUM 39                // the row of maze
#define COL_NUM 39                // the column of maze
#define MAX_MAP_NUM 2             // maximum numbers of map file
#define FILENAME_SUFFIX_LEN 2     // length of map filename's suffix
#define FILENAME_PREFIX "mazemap" // map filename's prefix
#define MAP_FILE_PATH "map/"      // the directory where store the map
#define FILENAME_LEN strlen(MAP_FILE_PATH) + strlen(FILENAME_PREFIX) 
                     + FILENAME_SUFFIX_LEN // length of map filename

typedef struct
{
  int x;
  int y;
}PosType;

typedef struct
{
  int m, n;
  int maze[ROW_NUM][COL_NUM];
}MazeType;

/*
 * Loading the maze data from random map file.
 */
int LoadMaze(MazeType& maze, PosType& entry, PosType& exit)
{
  srandom(time(NULL));          // random seed

  int mapnumInt = random() % 
                  MAX_MAP_NUM + 1; // 1 <= mapnum <= MAX_MAP_NUM
  char* mapfile = (char*) malloc(sizeof(char) 
                  * (FILENAME_LEN + 1)); // store the map filename
  char* mapnumStr = (char*) malloc(sizeof(char) * (FILENAME_SUFFIX_LEN 
                    + 1)); // store character type map number

  /*
   * Convert the integer type map number to character,
   * and store as a string.
   */
  if (mapnumInt < 10)
  {
    mapnumStr[0] = '0';
    mapnumStr[1] = (char) (mapnumInt + '0');
  }
  else
  {
    mapnumStr[0] = (char) (mapnumInt / 10 + '0');
    mapnumStr[1] = (char) (mapnumInt % 10 + '0');
  }
  mapnumStr[FILENAME_SUFFIX_LEN] = '\0';

  /*
   * Store the filename.
   */
  mapfile = strcat(mapfile, MAP_FILE_PATH);
  mapfile = strcat(mapfile, FILENAME_PREFIX);
  mapfile = strcat(mapfile, mapnumStr);

  /*
   * Open the map file.
   */
  FILE* fp = fopen(mapfile, "r");
  if (!fp)
    return 1;

  /*
   * Store the data to 'maze' array.
   */
  int i, j;
  for (i = 0; i != ROW_NUM; ++i)
  {
    for (j = 0; j != COL_NUM; ++j)
    {
      fscanf(fp, "%d", &maze.maze[i][j]);
      fseek(fp, 1, SEEK_CUR); // the offset is relative to 
                              // the current position indicator
    }
  }

  /*
   * Get the coordinate of entry and exit.
   */
  fscanf(fp, "%d", &entry.x);
  fseek(fp, 1, SEEK_CUR);
  fscanf(fp, "%d", &entry.y);
  fseek(fp, 1, SEEK_CUR);
  fscanf(fp, "%d", &exit.x);
  fseek(fp, 1, SEEK_CUR);
  fscanf(fp, "%d", &exit.y);

  /*
   * Release the space.
   */
  if (!mapfile)
    free(mapfile);
  if (!mapnumStr)
    free(mapnumStr);
  mapfile = NULL;
  mapnumStr = NULL;

  fclose(fp);

  return 0;
}
\end{verbatim}
\end{shaded}
\end{document}
